import React, { useCallback, useMemo, useRef, useState } from "react";
import { Select, Spin, Avatar, Pagination } from "antd";
import type { SelectProps } from "antd";
import debounce from "lodash/debounce";

interface PaginationSelectProps<ValueType = any>
  extends Omit<SelectProps<ValueType | ValueType[]>, "options" | "children"> {
  fetchOptions: (params: {
    page: number;
    pageSize: number;
    keyword: string;
  }) => Promise<{
    list: ValueType[];
    total: number;
  }>;
  pageSize: number;
  debounceTimeout?: number;
}

const PaginationSelect = <
  ValueType extends {
    key?: string;
    label: React.ReactNode;
    value: string | number;
    avatar?: string;
  } = any
>(
  props: PaginationSelectProps<ValueType>
) => {
  const {
    fetchOptions,
    pageSize,
    debounceTimeout = 3000,
    ...restProps
  } = props;
  const [loading, setLoading] = useState(false);
  const [options, setOptions] = useState<ValueType[]>([]);
  const [currentPage, setCurrentPage] = useState(1);
  const [total, setTotal] = useState(0);
  const [searchKeyword, setSearchKeyword] = useState("");
  const fetchRef = useRef(0);
  const loadData = useCallback(
    async (value: string, page: number) => {
      fetchRef.current += 1;
      const fetchId = fetchRef.current;
      setOptions([]);
      setLoading(true);
      const { list, total } = await fetchOptions({
        page,
        pageSize,
        keyword: value,
      });
      if (fetchId !== fetchRef.current) {
        return;
      }
      setLoading(false);
      setOptions(list);
      setCurrentPage(page);
      setTotal(total);
      setSearchKeyword(value);
    },
    [fetchOptions, pageSize]
  );
  const debounceFetcher = useMemo(() => {
    const loadOptions = async (value: string) => {
      await loadData(value, 1);
    };
    return debounce(loadOptions, debounceTimeout);
  }, [loadData, debounceTimeout]);
  const handlePageChange = async (page: number) => {
    await loadData(searchKeyword, page);
  };
  const renderDropDown = (menu: React.ReactNode) => {
    return (
      <>
        {menu}
        {total > 0 && (
          <Pagination
            align="center"
            simple={{ readOnly: true }}
            showSizeChanger={false}
            current={currentPage}
            total={total}
            onChange={handlePageChange}
          />
        )}
      </>
    );
  };
  return (
    <Select
      labelInValue
      filterOption={false}
      onSearch={debounceFetcher}
      notFoundContent={loading ? <Spin size="small" /> : null}
      {...restProps}
      options={options}
      optionRender={(option) => (
        <div style={{ display: "flex", alignItems: "center" }}>
          {option.data.avatar && (
            <Avatar src={option.data.avatar} style={{ marginRight: 8 }} />
          )}
          {option.label}
        </div>
      )}
      popupRender={renderDropDown}
    />
  );
};

export default PaginationSelect;
